import * as io from 'socket.io';
import * as socketioJwt from 'socketio-jwt';
import { config } from './config';
import * as glob from 'glob';
import * as path from 'path';
import { defaultMetadataRegistry } from 'event-dispatch/MetadataRegistry';
import { CustomError } from '../common/customError';
import { logger } from '../common/logger';

// include subscribers dynamically
// let files = glob.sync('./dist/subscribers/*.js');
// files.map(f => { return require(path.resolve(f)); });

import('../subscribers/UserSubscriber');

export function setupSockets(app) {
    let server = io(app, { path: '/socket.io' });

    // use jwt
    server.use(socketioJwt.authorize({
        secret: config.auth.jwt_secret,
        handshake: true
    }));

    server.use((socket: any, next) => {
        socket.request.user = socket.decoded_token;
        return next();
    });

    server.on('connection', (socket) => {
        logger.info(`Socket ${socket.id} connection`);

        // bind applicable subscribers to the socket
        defaultMetadataRegistry
            .collectEventsHandlers
            .forEach(eventHandler => {
                const eventNamesForThisHandler = Object.keys(eventHandler);
                eventNamesForThisHandler.forEach(eventName => {
                    const callback = eventHandler[eventName];
                    socket.on(eventName, (req, cb) => {
                        try {
                            if (typeof req == 'function') {
                                cb = req;
                                req = null;
                            }

                            const res = callback({ socket, req });
                            if (typeof cb == 'function') cb({ success: true, res });
                        } catch (error) {
                            logger.error(`event eventName err: ${error}`);
                            if (!(error instanceof CustomError)) {
                                error = new CustomError('unexpected error', error.message || error.stack);
                            }

                            if (typeof cb == 'function') cb({ success: false, error: error.toJSON() });
                        }
                    });
                });
            });
    });

    return io;
}
